#include <windows.h>
#include <ximera/config.hpp>
#include <ximera/input/dinput8/plugin.hpp>

#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dinput8.lib")

namespace ximera { namespace input { namespace dinput8
{
    extern HINSTANCE DllInstance = NULL;

    String HResultToString(HRESULT hr)
    {
        String res = L"Unknown error";

        switch (hr)
        {
        case S_FALSE:
            res = L"Can't do that.";
            break;

        case DI_DOWNLOADSKIPPED: 
            res = L"The parameters of the effect were successfully updated, but the effect could not be downloaded because the associated device was not acquired in exclusive mode.";
            break;

        case DI_EFFECTRESTARTED:
            res = L"The effect was stopped, the parameters were updated, and the effect was restarted.";
            break;

        case DI_OK:
            res = L"The operation completed successfully. This value is equal to the S_OK standard COM return value.";
            break;

        case DI_POLLEDDEVICE:
            res = L"The device is a polled device. As a result, device buffering does not collect any data and event notifications is not signaled until the IDirectInputDevice8 Interface method is called.";
            break;

        case DI_SETTINGSNOTSAVED:
            res = L"The action map was applied to the device, but the settings could not be saved.";
            break;

        case DI_TRUNCATED:
            res = L"The parameters of the effect were successfully updated, but some of them were beyond the capabilities of the device and were truncated to the nearest supported value.";
            break;

        case DI_TRUNCATEDANDRESTARTED:
            res = L"Equal to DI_EFFECTRESTARTED | DI_TRUNCATED.";
            break;

        case DI_WRITEPROTECT:
            res = L"A SUCCESS code indicating that settings cannot be modified.";
            break;

        case DIERR_ACQUIRED:
            res = L"The operation cannot be performed while the device is acquired.";
            break;

        case DIERR_ALREADYINITIALIZED:
            res = L"This object is already initialized";
            break;

        case DIERR_BADDRIVERVER:
            res = L"The object could not be created due to an incompatible driver version or mismatched or incomplete driver components.";
            break;

        case DIERR_BETADIRECTINPUTVERSION:
            res = L"The application was written for an unsupported prerelease version of DirectInput.";
            break;

        case DIERR_DEVICEFULL:
            res = L"The device is full.";
            break;

        case DIERR_DEVICENOTREG:
            res = L"The device or device instance is not registered with DirectInput. This value is equal to the REGDB_E_CLASSNOTREG standard COM return value.";
            break;

        case DIERR_EFFECTPLAYING:
            res = L"The parameters were updated in memory but were not downloaded to the device because the device does not support updating an effect while it is still playing.";
            break;

        case DIERR_GENERIC:
            res = L"An undetermined error occurred inside the DirectInput subsystem. This value is equal to the E_FAIL standard COM return value.";
            break;

        case DIERR_HASEFFECTS:
            res = L"The device cannot be reinitialized because effects are attached to it.";
            break;

        case DIERR_INCOMPLETEEFFECT:
            res = L"The effect could not be downloaded because essential information is missing. For example, no axes have been associated with the effect, or no type-specific information has been supplied.";
            break;

        case DIERR_INPUTLOST:
            res = L"Access to the input device has been lost. It must be reacquired.";
            break;

        case DIERR_INVALIDPARAM:
            res = L"An invalid parameter was passed to the returning function, or the object was not in a state that permitted the function to be called. This value is equal to the E_INVALIDARG standard COM return value.";
            break;

        case DIERR_MAPFILEFAIL:
            res = L"An error has occurred either reading the vendor-supplied action-mapping file for the device or reading or writing the user configuration mapping file for the device.";
            break;

        case DIERR_MOREDATA:
            res = L"Not all the requested information fit into the buffer.";
            break;

        case DIERR_NOAGGREGATION:
            res = L"This object does not support aggregation.";
            break;

        case DIERR_NOINTERFACE:
            res = L"The object does not support the specified interface. This value is equal to the E_NOINTERFACE standard COM return value.";
            break;

        case DIERR_NOTACQUIRED:
            res = L"The operation cannot be performed unless the device is acquired.";
            break;

        case DIERR_NOTBUFFERED:
            res = L"The device is not buffered. Set the DIPROP_BUFFERSIZE property to enable buffering.";
            break;

        case DIERR_NOTDOWNLOADED:
            res = L"The effect is not downloaded.";
            break;

        case DIERR_NOTEXCLUSIVEACQUIRED:
            res = L"The operation cannot be performed unless the device is acquired in DISCL_EXCLUSIVE mode.";
            break;

        case DIERR_NOTFOUND:
            res = L"The requested object does not exist.";
            break;

        case DIERR_NOTINITIALIZED:
            res = L"This object has not been initialized.";
            break;

        case DIERR_OLDDIRECTINPUTVERSION:
            res = L"The application requires a newer version of DirectInput.";
            break;

        case E_ACCESSDENIED:
            res = L"Access denied.";
            break;

        case DIERR_OUTOFMEMORY:
            res = L"The DirectInput subsystem could not allocate sufficient memory to complete the call. This value is equal to the E_OUTOFMEMORY standard COM return value.";
            break;

        case DIERR_REPORTFULL:
            res = L"More information was requested to be sent than can be sent to the device.";
            break;

        case DIERR_UNPLUGGED:
            res = L"The operation could not be completed because the device is not plugged in.";
            break;

        case DIERR_UNSUPPORTED:
            res = L"The function called is not supported at this time. This value is equal to the E_NOTIMPL standard COM return value.";
            break;

        case E_HANDLE:
            res = L"The HWND parameter is not a valid top-level window that belongs to the process.";
            break;

        case E_PENDING:
            res = L"Data is not yet available.";
            break;

        case E_POINTER:
            res = L"An invalid pointer, usually NULL, was passed as a parameter.";
            break;
        }

        return res;
    }
}}}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
    ximera::input::dinput8::DllInstance = static_cast<HINSTANCE>(hModule);

	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
    return TRUE;
}

extern "C" XIMERA_PLUGIN_API ximera::system::IPlugin* ximera_initPlugin(void)
{
    return ximera::input::dinput8::Plugin::getInstance();
}
